#include "TriMesh.h"
#include "Renderer.h"
#include "GeometryDataManager.h"

namespace Nezha
{

	TriMesh::TriMesh(GeometryData* gd)
		:RenderMesh(gd)
	{

	}

	TriMesh::~TriMesh()
	{
	}

	void TriMesh::updateNormals()
	{	
		VertexBufferAccessor vba;

		if(!vba.beginAccess(mGeometryDataPtr))
		{
			return;
		}

		const VertexElement* veNormal = mGeometryDataPtr->getVertexDecl().getElementByVS(VS_NORMAL);
		if(!veNormal)
		{
			NZWarning(NZ_SOURCE_TRACK(Geometry decl has no normal));
			vba.endAccess();
			return;
		}

		VertexBufferPtr vb = mGeometryDataPtr->getVertexBuffer(veNormal->StreamIndex);
		u32 numVerts = vb->getNumVertex();
		u32 i = 0;
		const VertexBufferAccessor::VertexElemBinding* veb_norm = vba.getElemBindingByVS(VS_NORMAL);
		const VertexBufferAccessor::VertexElemBinding* veb_pos = vba.getElemBindingByVS(VS_POSITION);

		if(!veb_pos || !veb_norm)
		{
			NZError(NZ_SOURCE_TRACK(Geometry has no position channel and normal channel!));
		}

		for(; i < numVerts; i ++)
		{
			Vector3& v = vba.accessChannel<Vector3>(*veb_norm, i);
			v = Vector3::ZERO;
		}

		u32 numTris = getNumTriangles();
		_Triangle tri;
		Vector3 eg1;
		Vector3 eg2;
		Vector3 normal;

		int* indices = vba.accessIndices();

		// DEBUG
		Vector3 vv0, vv1, vv2;

		for(u32 i = 0; i < numTris; i++)
		{
			if(!getTriangle(i, tri, indices))
			{
				continue;
			}

			Vector3& v = vba.accessChannel<Vector3>(*veb_pos, tri.index1);
			Vector3& v1 = vba.accessChannel<Vector3>(*veb_pos, tri.index2);
			Vector3& v2 = vba.accessChannel<Vector3>(*veb_pos, tri.index3);

			vv0 = v;
			vv1 = v1;
			vv2 = v2;

			eg1 = v1 - v;
			eg2 = v2 - v;
			normal = eg1.cross(eg2);

			Vector3& n = vba.accessChannel<Vector3>(*veb_norm, tri.index1);
			Vector3& n1 = vba.accessChannel<Vector3>(*veb_norm, tri.index2);
			Vector3& n2 = vba.accessChannel<Vector3>(*veb_norm, tri.index3);

			n += normal;
			n1 += normal;
			n2 += normal;
		}

		for(; i < numVerts; i ++)
		{
			Vector3& v = vba.accessChannel<Vector3>(*veb_norm, i);
			v.normalize();
		}

		vba.endAccess();
	}

	void TriMesh::updateTangents(u32 tangentSpace)
	{
		// TODO
	}


	TriangleListMesh::TriangleListMesh(GeometryData* gd, bool recacuNormal)
		:TriMesh(gd)
	{
		if(recacuNormal)
		{
			updateNormals();
		}
	}

	u32 TriangleListMesh::getNumTriangles() const
	{
		if(mGeometryDataPtr.ptr() && mGeometryDataPtr->getIndexBuffer().ptr())
		{
			return mGeometryDataPtr->getIndexBuffer()->getNumIndices() / 3;
		}

		return 0;
	}

	bool TriangleListMesh::getTriangle(u32 i, u32& i1, u32& i2, u32& i3, int* indices) const
	{
		if(!mGeometryDataPtr)
		{
			return false;
		}

		if(i < getNumTriangles())
		{
			IndexBuffer::IndexType it = mGeometryDataPtr->getIndexBuffer()->getIndexType();
			if(it == IndexBuffer::IT_16BIT)
			{
				u16* p = ((u16*)indices) + 3 * i;
				i1 = *p++;
				i2 = *p++;
				i3 = *p;
			}
			else
			{
				int* p = indices + 3 * i;
				i1 = *p++;
				i2 = *p++;
				i3 = *p;
			}

			return true;
		}

		return false;
	}

	/** helper for default vd info. */
	static void _Internal_PrepareVeb(float* fvb, u32 stride, TriangleListMesh::Helper& h)
	{
		u32 offset = 0;
		h.posVeb.Data = fvb;
		h.posVeb.BufferStride = stride;

		offset += VertexDeclaration::ElementTypeCount(VET_FLOAT3);
		h.normVeb.Data = fvb + offset;
		h.normVeb.BufferStride = stride;

		offset += VertexDeclaration::ElementTypeCount(VET_FLOAT3);
		h.texVeb.Data = fvb + offset;
		h.texVeb.BufferStride = stride;

		offset += VertexDeclaration::ElementTypeCount(VET_FLOAT2);
		h.tex2Veb.Data = fvb + offset;
		h.tex2Veb.BufferStride = stride;
	}

	TriangleListMesh* TriangleListMesh::CreatePlane(u32 xSamples, u32 ySamples, float w /* = 1.0f */, float h /* = 1.0f */)
	{
		if(xSamples < 2)
		{
			xSamples = 2;
		}

		if(ySamples < 2)
		{
			ySamples = 2;
		}

		float halfW = w * 0.5f;
		float halfH = h * 0.5f;
		u32 numVertexs = xSamples * ySamples;
		u32 numTriangles = 2 * (xSamples - 1) * (ySamples - 1);

		VertexDeclaration vd;
		GetDefaultTLMVertexDecl(vd);

		u32 stride = vd.getStride();
		u32 vbSize = numVertexs * stride;
		u32 numIndices = numTriangles * 3;
		u32 ibSize = numIndices * sizeof(u16);

		float* fvb = (float*)NZMalloc(vbSize);
		u16* uib = (u16*)NZMalloc(ibSize);

		VertexBufferAccessor vba;
		Helper helper;

		_Internal_PrepareVeb(fvb, stride, helper);

		float invU = 1.0f / (xSamples - 1.0f);
		float invV = 1.0f / (ySamples - 1.0f);
		float u, v;
		u32 i, ix, iy;
		float fx, fy;

		for(iy = 0, i = 0; iy < ySamples; iy++)
		{
			v = iy*invV;
			fy = (2.0f*v - 1.0f)*halfH;
			for(ix = 0; ix < xSamples; ix++)
			{
				u = ix*invU;
				fx = (2.0f*u - 1.0f)*halfW;
				Vector3& pos = vba.accessChannel<Vector3>(helper.posVeb, i);
				pos.x = fx;
				pos.y = fy;
				pos.z = 0.0f;

				Vector3& norm = vba.accessChannel<Vector3>(helper.normVeb, i);
				norm.set(0, 0, 1.0f);

				Vector2& tex = vba.accessChannel<Vector2>(helper.texVeb, i);
				Vector2& tex2 = vba.accessChannel<Vector2>(helper.tex2Veb, i);

				tex.x = tex2.x = u;
				tex.y = tex2.y = v;

				i++;
			}
		}

		u16 i0, i1, i2, i3;
		for(iy = 0, i = 0; iy < ySamples - 1; iy++)
		{
			for(ix = 0; ix < xSamples - 1; ix++)
			{
				i0 = ix + xSamples * iy;
				i1 = i0 + 1;
				i2 = i1 + xSamples;
				i3 = i0 + xSamples;
				uib[i++] = i0;
				uib[i++] = i1;
				uib[i++] = i2;
				uib[i++] = i0;
				uib[i++] = i2;
				uib[i++] = i3;
			}
		}

		VertexBufferPtr vb = Renderer::GetGlobal()->getGeometryDataManager()->createVertexBuffer(stride, numVertexs, HardwareBuffer::HBU_STATIC, false, fvb);
		IndexBufferPtr ib = Renderer::GetGlobal()->getGeometryDataManager()->createIndexBuffer(HardwareBuffer::HBU_STATIC, IndexBuffer::IT_16BIT, numIndices, false, uib);

		GeometryData* gd = NZ_New GeometryData();
		gd->setVertexStream(0, vb);
		gd->setIndexBuffer(ib);
		gd->setVertexDeclaration(vd);

		TriangleListMesh* tlm = NZ_New TriangleListMesh(gd, false);

		const VertexElement* vePos = vd.getElementByVS(VS_POSITION);
		AABB aabb;
		aabb.fromVertexsData(numVertexs, vePos->Offset, vd.getStride(), (u8*)fvb);

		NZFree(uib);
		NZFree(fvb);

		return tlm;
	}

	TriangleListMesh* TriangleListMesh::CreateBox(float w, float h, float depth)
	{
		// just a box
		u32 numVertexs = 24;
		u32 numTriangles = 12;

		VertexDeclaration vd;
		GetDefaultTLMVertexDecl(vd);

		u32 stride = vd.getStride();
		u32 vbSize = numVertexs * stride;
		u32 numIndices = numTriangles * 3;
		u32 ibSize = numIndices * sizeof(u16);

		float* fvb = (float*)NZMalloc(vbSize);
		//u16* uib = (u16*)NZMalloc(ibSize);

		VertexBufferAccessor vba;
		Helper helper;

		_Internal_PrepareVeb(fvb, stride, helper);

		float fx = w * 0.5f;
		float fy = h * 0.5f;
		float fz = depth * 0.5f;
			
		vba.setVector3(helper.posVeb, 0, fx, -fy, fz);
		vba.setVector3(helper.posVeb, 1, -fx, -fy, fz);
		vba.setVector3(helper.posVeb, 2, fx, fy, fz);   
		vba.setVector3(helper.posVeb, 3, -fx, fy, fz);
		vba.setVector3(helper.posVeb, 4, fx, fy, -fz);
		vba.setVector3(helper.posVeb, 5, -fx, fy, -fz);
		vba.setVector3(helper.posVeb, 6, fx, -fy, -fz);
		vba.setVector3(helper.posVeb, 7, -fx, -fy, -fz);
		vba.setVector3(helper.posVeb, 8, fx, fy, fz); 
		vba.setVector3(helper.posVeb, 9, -fx, fy, fz);
		vba.setVector3(helper.posVeb, 10, fx, fy, -fz);
		vba.setVector3(helper.posVeb, 11, -fx, fy, -fz);  
		vba.setVector3(helper.posVeb, 12, fx, -fy, -fz);
		vba.setVector3(helper.posVeb, 13, -fx, -fy, fz);
		vba.setVector3(helper.posVeb, 14, -fx, -fy, -fz);	   
		vba.setVector3(helper.posVeb, 15, fx, -fy, fz);
		vba.setVector3(helper.posVeb, 16, -fx, -fy, fz);
		vba.setVector3(helper.posVeb, 17, -fx, fy, -fz);   
		vba.setVector3(helper.posVeb, 18, -fx, -fy, -fz);
		vba.setVector3(helper.posVeb, 19, -fx, fy, fz);
		vba.setVector3(helper.posVeb, 20, fx, -fy, -fz);		   
		vba.setVector3(helper.posVeb, 21, fx, fy, fz);
		vba.setVector3(helper.posVeb, 22, fx, -fy, fz);
		vba.setVector3(helper.posVeb, 23, fx, fy, -fz);		   

		vba.setVector3(helper.normVeb, 0, 0.0f, 0.0f, 1.0f);
		vba.setVector3(helper.normVeb, 1, 0.0f, 0.0f, 1.0f);
		vba.setVector3(helper.normVeb, 2, 0.0f, 0.0f, 1.0f);
		vba.setVector3(helper.normVeb, 3, 0.0f, 0.0f, 1.0f);
		vba.setVector3(helper.normVeb, 4, 0.0f, 1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 5, 0.0f, 1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 6, 0.0f, 0.0f, -1.0f);
		vba.setVector3(helper.normVeb, 7, 0.0f, 0.0f, -1.0f);
		vba.setVector3(helper.normVeb, 8, 0.0f, 1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 9, 0.0f, 1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 10, 0.0f, 0.0f, -1.0f);
		vba.setVector3(helper.normVeb, 11, 0.0f, 0.0f, -1.0f);
		vba.setVector3(helper.normVeb, 12, 0.0f, -1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 13, 0.0f, -1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 14, 0.0f, -1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 15, 0.0f, -1.0f, 0.0f);
		vba.setVector3(helper.normVeb, 16, -1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 17, -1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 18, -1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 19, -1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 20, 1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 21, 1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 22, 1.0f, 0.0f, 0.0f);
		vba.setVector3(helper.normVeb, 23, 1.0f, 0.0f, 0.0f);

		vba.setVector2(helper.texVeb, 0, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 1, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 2, 0.0f, 1.0f);
		vba.setVector2(helper.texVeb, 3, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 4, 0.0f, 1.0f);
		vba.setVector2(helper.texVeb, 5, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 6, 0.0f, 1.0f);
		vba.setVector2(helper.texVeb, 7, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 8, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 9, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 10, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 11, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 12, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 13, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 14, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 15, 0.0f, 1.0f);
		vba.setVector2(helper.texVeb, 16, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 17, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 18, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 19, 0.0f, 1.0f);
		vba.setVector2(helper.texVeb, 20, 0.0f, 0.0f);
		vba.setVector2(helper.texVeb, 21, 1.0f, 1.0f);
		vba.setVector2(helper.texVeb, 22, 1.0f, 0.0f);
		vba.setVector2(helper.texVeb, 23, 0.0f, 1.0f);

		vba.setVector2(helper.tex2Veb, 0, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 1, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 2, 0.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 3, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 4, 0.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 5, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 6, 0.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 7, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 8, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 9, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 10, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 11, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 12, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 13, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 14, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 15, 0.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 16, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 17, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 18, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 19, 0.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 20, 0.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 21, 1.0f, 1.0f);
		vba.setVector2(helper.tex2Veb, 22, 1.0f, 0.0f);
		vba.setVector2(helper.tex2Veb, 23, 0.0f, 1.0f);

		u16 uib[] =
		{
		   1, 0, 3,
		   3, 0, 2,
		   9, 8, 5,
		   5, 8, 4,
		   11, 10, 7,
		   7, 10, 6,
		   14, 12, 13,
		   13, 12, 15,
		   18, 16, 17,
		   17, 16, 19,
		   22, 20, 21,
		   21, 20, 23
		};

		VertexBufferPtr vb = Renderer::GetGlobal()->getGeometryDataManager()->createVertexBuffer(stride, numVertexs, HardwareBuffer::HBU_STATIC, false, fvb);
		IndexBufferPtr ib = Renderer::GetGlobal()->getGeometryDataManager()->createIndexBuffer(HardwareBuffer::HBU_STATIC, IndexBuffer::IT_16BIT, numIndices, false, uib);

		GeometryData* gd = NZ_New GeometryData();
		gd->setVertexStream(0, vb);
		gd->setIndexBuffer(ib);
		gd->setVertexDeclaration(vd);

		TriangleListMesh* tlm = NZ_New TriangleListMesh(gd, false);

		const VertexElement* vePos = vd.getElementByVS(VS_POSITION);
		AABB aabb;
		aabb.fromVertexsData(numVertexs, vePos->Offset, vd.getStride(), (u8*)fvb);

		//NZFree(uib);
		NZFree(fvb);

		return tlm;
	}

	TriangleListMesh* TriangleListMesh::CreateSphere(u32 zSamples, u32 radialSamples, float radius)
	{
		u32 zSam1 = zSamples - 1;
		u32 zSam2 = zSamples - 2;
		u32 zSam3 = zSamples - 3;
		u32 rsp1 = radialSamples + 1;
		u32 numVertexs = zSam2 * rsp1 + 2;
		u32 numTriangles = 2 * zSam2 * radialSamples;

		VertexDeclaration vd;
		GetDefaultTLMVertexDecl(vd);

		u32 stride = vd.getStride();
		u32 vbSize = numVertexs * stride;
		u32 numIndices = numTriangles * 3;
		u32 ibSize = numIndices * sizeof(u16);

		float* fvb = (float*)NZMalloc(vbSize);
		u16* uib = (u16*)NZMalloc(ibSize);

		VertexBufferAccessor vba;
		Helper helper;

		_Internal_PrepareVeb(fvb, stride, helper);

		float invRS = 1.0f / (float)radialSamples;
		float zFactor = 2.0f / zSam1;
		u32 r, z, zStart, i;
		Vector2 tex;
		float* sinArr = NZ_New float[rsp1];
		float* cosArr = NZ_New float[rsp1];
		for(r = 0; r < radialSamples; r++)
		{
			float angle = NZ_2PI * invRS * r;
			cosArr[r] = Cos(angle);
			sinArr[r] = Sin(angle);
		}

		sinArr[radialSamples] = sinArr[0];
		cosArr[radialSamples] = cosArr[0];
		Vector3* vec3;
		Vector2* vec2;
		for(z = 1, i = 0; z < zSam1; z++)
		{
			float zFrac = -1.0f + zFactor * z; // in (-1, 1
			float fz = radius * zFrac;

			Vector3 sliceCenter(0, 0, fz);
			float sliceRadius = Sqrt(fabs(radius * radius - fz * fz));
			Vector3 normal;
			u32 iSave = i;
			for(r = 0; r < radialSamples; r++)
			{
				float radialFrac = r * invRS;
				Vector3 vRadial(cosArr[r], sinArr[r], 0);
				vec3 = vba.accessChannelPtr<Vector3>(helper.posVeb, i);
				*vec3 = sliceCenter + sliceRadius * vRadial;

				Vector3* vecNormal = vba.accessChannelPtr<Vector3>(helper.normVeb, i);
				vecNormal->normalize();

				vec2 = vba.accessChannelPtr<Vector2>(helper.texVeb, i);
				*vec2 = Vector2(radialFrac, 0.5f * (zFrac + 1.0f));
				vec2 = vba.accessChannelPtr<Vector2>(helper.tex2Veb, i);
				*vec2 = Vector2(radialFrac, 0.5f * (zFrac + 1.0f));

				++i;
			}

			vec3 = vba.accessChannelPtr<Vector3>(helper.posVeb, i);
			Vector3* vecSave = vba.accessChannelPtr<Vector3>(helper.posVeb, iSave);
			*vec3 = *vecSave;
			vec3 = vba.accessChannelPtr<Vector3>(helper.normVeb, i);
			vecSave = vba.accessChannelPtr<Vector3>(helper.normVeb, iSave);
			*vec3 = *vecSave;

			tex = Vector2(1.0f, 0.5f * (zFrac + 1.0f));
			vec2 = vba.accessChannelPtr<Vector2>(helper.texVeb, i);
			*vec2 = tex;
			vec2 = vba.accessChannelPtr<Vector2>(helper.tex2Veb, i);
			*vec2 = tex;

			++i;
		}

		// south pole
		vec3 = vba.accessChannelPtr<Vector3>(helper.posVeb, i);
		*vec3 = -radius * Vector3::UNIT_Z;
		vec3 = vba.accessChannelPtr<Vector3>(helper.normVeb, i);
		*vec3 = Vector3::UNIT_Z;

		tex = Vector2(0.5f, 0.5f);
		vec2 = vba.accessChannelPtr<Vector2>(helper.texVeb, i);
		*vec2 = tex;
		vec2 = vba.accessChannelPtr<Vector2>(helper.tex2Veb, i);
		*vec2 = tex;

		++i;

		// north pole
		vec3 = vba.accessChannelPtr<Vector3>(helper.posVeb, i);
		*vec3 = radius * Vector3::UNIT_Z;
		vec3 = vba.accessChannelPtr<Vector3>(helper.normVeb, i);
		*vec3 = Vector3::UNIT_Z;

		tex = Vector2(0.5f, 1.0f);
		vec2 = vba.accessChannelPtr<Vector2>(helper.texVeb, i);
		*vec2 = tex;
		vec2 = vba.accessChannelPtr<Vector2>(helper.tex2Veb, i);
		*vec2 = tex;

		++i;

		NZ_ASSERT(i == numVertexs);

		// generate indices
		u16* indices = uib;
		for (z = 0, zStart = 0; z < zSam3; z++)
		{
			u16 i0 = zStart;
			u16 i1 = i0 + 1;
			zStart += rsp1;
			u16 i2 = zStart;
			u16 i3 = i2 + 1;
			for (i = 0; i < radialSamples; i++, indices += 6)
			{
				indices[0] = i0++;
				indices[1] = i1;
				indices[2] = i2;
				indices[3] = i1++;
				indices[4] = i3++;
				indices[5] = i2++;
			}
		}

		// south pole triangles
		u32 southPole = numTriangles - 2;
		for (i = 0; i < radialSamples; i++, indices += 3)
		{
			indices[0] = i;
			indices[1] = southPole;
			indices[2] = i+1;
		}

		// north pole triangles
		u32 northPole = numVertexs - 1, indexOffsetTmp = zSam3 * rsp1;
		for (i = 0; i < radialSamples; i++, indices += 3)
		{
			indices[0] = i+indexOffsetTmp;
			indices[1] = i+1+indexOffsetTmp;
			indices[2] = northPole;
		}

		NZ_ASSERT(indices == uib + 3 * numTriangles);

		VertexBufferPtr vb = Renderer::GetGlobal()->getGeometryDataManager()->createVertexBuffer(stride, numVertexs, HardwareBuffer::HBU_STATIC, false, fvb);
		IndexBufferPtr ib = Renderer::GetGlobal()->getGeometryDataManager()->createIndexBuffer(HardwareBuffer::HBU_STATIC, IndexBuffer::IT_16BIT, numIndices, false, uib);

		NZ_Delete[] sinArr;
		NZ_Delete[] cosArr;

		GeometryData* gd = NZ_New GeometryData();
		gd->setVertexStream(0, vb);
		gd->setIndexBuffer(ib);
		gd->setVertexDeclaration(vd);

		TriangleListMesh* tlm = NZ_New TriangleListMesh(gd, false);

		const VertexElement* vePos = vd.getElementByVS(VS_POSITION);
		AABB aabb;
		aabb.fromVertexsData(numVertexs, vePos->Offset, vd.getStride(), (u8*)fvb);

		NZFree(uib);
		NZFree(fvb);

		return tlm;
	}

	void TriangleListMesh::GetDefaultTLMVertexDecl(VertexDeclaration& vd)
	{
		vd.clear();

		u16 offset = 0;
		vd.addElement(0, 0, VS_POSITION, VET_FLOAT3, 0, false);
		offset += VertexDeclaration::ElementTypeSize(VET_FLOAT3);
		vd.addElement(0, offset, VS_NORMAL, VET_FLOAT3, 0, false);
		offset += VertexDeclaration::ElementTypeSize(VET_FLOAT3);
		vd.addElement(0, offset, VS_TEXCOORD, VET_FLOAT2, 0, false);
		offset += VertexDeclaration::ElementTypeSize(VET_FLOAT2);
		vd.addElement(0, offset, VS_TEXCOORD, VET_FLOAT2, 0, true);
	}

	void TriangleListMesh::SetDefaultTLMVertexDcalMask(u32 vdMask)
	{
		// TODO
	}


	TriangleStripMesh::TriangleStripMesh(GeometryData* gd, bool recacuNormal)
		:TriMesh(gd)
	{
		if(recacuNormal)
		{
			updateNormals();
		}
	}

	// override
	u32 TriangleStripMesh::getNumTriangles() const
	{
		if(mGeometryDataPtr.notNull() && mGeometryDataPtr->getIndexBuffer().notNull())
		{
			return mGeometryDataPtr->getIndexBuffer()->getNumIndices() - 2;
		}

		return 0;
	}

	bool TriangleStripMesh::getTriangle(u32 i, u32& i1, u32& i2, u32& i3, int* indices) const
	{
		u32 numTriangles = getNumTriangles();

		// for standard strip arrangement.
		/*
			0 ------ 1 ------ 4
			|		/|		 /|
			|	   / |		/ |
			|	  /	 |     /  |
			|	 /	 |	  /	  |
			|	/	 |	 /	  |
			|  /	 |  /	  |
			| /		 | /	  |
			|/		 |/		  |
			2 ------ 3 ------ 5
		*/

		if (i < numTriangles)
		{
			i1 = indices[i];
			if (i & 1)
			{
				i2 = indices[i + 2];
				i3 = indices[i + 1];
			}
			else
			{
				i2 = indices[i + 1];
				i3 = indices[i + 2];
			}

			return (i1 != i2 && i1 != i3 && i2 != i3);
		}

		return false;	
	}

}//end namespace Nezha